home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume91
/
midi
/
casio
/
part01
/
casio.c
next >
Wrap
C/C++ Source or Header
|
1991-03-28
|
11KB
|
421 lines
/* casio - download sample data from a casio fz-1 */
/* Copyright (C) 1988 Hackercorp. All Rights Reserved */
#include <libraries/dos.h>
#include <clib/macros.h>
#include <midi/midi.h>
#include <functions.h>
#include <stdio.h>
#include <devices/timer.h>
#include "casio.h"
#include "prototypes.h"
char *program_name = "casio fz1 download program";
#define CheckMsg(m) (m->mp_MsgList.lh_Head->ln_Succ != 0)
extern struct timerequest *timer_request;
/* message ids for fz-1 system exclusive messages */
#define OPEN_MIDI_MSG 0x70
#define CLOSE_MIDI_MSG 0x71
#define OK_MIDI_MSG 0x72
#define ERR_MIDI_MSG 0x73
#define DATA_MIDI_MSG 0x74
#define EFFECT_MIDI_MSG 0x76
#define REMOTE_MIDI_MSG 0x7f
/* additional messages I define as responses from its_an_fz1_message */
#define NOT_A_FZ_MESSAGE 0
#define NOT_THE_REQUESTED_FZ_CHANNEL 1
#define DATA_ERROR 2
/* states for the i/o loop */
#define WAITING_FOR_OPEN 0
#define READING_FZ_DATA 1
#define MAX_RETRIES 10
#define CAPTURE_BUFFER_SIZE 16384
UBYTE capture_buffer[CAPTURE_BUFFER_SIZE];
void *MidiBase = NULL;
void *IntuitionBase = NULL;
struct MDest *dest = NULL;
struct MSource *source = NULL;
struct MRoute *route_a = NULL;
struct MRoute *route_b = NULL;
UBYTE *msg; /* buffer this in case we get shut down before freeing the current message */
int capture_position = 0;
void midi_cleanup(void)
{
/* if (msg)
FreeMidiMsg(msg); */
if (IntuitionBase)
CloseLibrary(IntuitionBase);
if (dest)
DeleteMDest(dest);
if (source)
DeleteMSource(source);
if (route_a)
DeleteMRoute(route_a);
if (route_b)
DeleteMRoute(route_b);
if (MidiBase)
CloseLibrary(MidiBase);
}
/* if channel is -1, any channel is ok (within FZ-1 System Exclusive message) */
/* validate the incoming message, including all sorts of stuff about the header
* and anything we know specifically within the message type as well */
UBYTE its_an_fz1_message(UBYTE *msg, int requested_channel)
{
int channel, length, expected_length;
struct FZ1_Message *p;
p = (struct FZ1_Message *)msg;
/* compare first bytes of message,
extract channel number and verify,
return function code
*/
length = MidiMsgLength(msg);
if ((p->casio_id != 0x44) || (p->fz1_id != 0x200)
|| ((p->encoded_channel & 0xf0) != 0x70))
return(NOT_A_FZ_MESSAGE);
channel = (p->encoded_channel & 0x0f);
if ((requested_channel != -1) && (channel != requested_channel))
return(NOT_THE_REQUESTED_FZ_CHANNEL);
switch(p->command)
{
case OPEN_MIDI_MSG:
expected_length = 16;
break;
case CLOSE_MIDI_MSG:
expected_length = 7;
break;
case DATA_MIDI_MSG:
expected_length = 136;
if (length == expected_length && (p->body.datamsg.checksum != calc_checksum(p)))
{
fprintf(stderr,"checksum error, expected %x, saw %x\n",
p->body.datamsg.checksum,calc_checksum(p));
return(DATA_ERROR);
}
break;
/* haven't seen any of these yet */
case OK_MIDI_MSG:
case ERR_MIDI_MSG:
case EFFECT_MIDI_MSG:
case REMOTE_MIDI_MSG:
panic("got a message I don't know how to handle");
/* it wasn't a message we understood yet it had all the makings of
* being one, it must be garbled */
default:
return(DATA_ERROR);
}
if (length != expected_length)
return(DATA_ERROR);
return(p->command);
}
void commune_with_fz1(struct MSource *source, struct MDest *dest, int channel, int outfd)
{
long len;
UBYTE *ip;
int command, retry_count = 0;
int state = WAITING_FOR_OPEN;
ULONG waitflags;
int packets_received = 0, error_count = 0, done = 0;
struct FZ1_Message *p;
/* wait for a message or control-C or "done" control var to be set */
while ((!((waitflags = Wait(-1)) & SIGBREAKF_CTRL_C)) && !done)
{
/* if ((waitflags & SIGBREAKF_CTRL_D) && (state = READING_FZ_DATA))
{
printf("saw a ^d\n");
goto data_error;
} */
/* while there are messages to process, process messages */
while (!done && (msg = GetMidiMsg(dest)))
{
/* discard all but system exclusive data - should be done
* by the route, check someday to see if we can find our
* route and change it if it isn't */
if (*msg != MS_SYSEX)
goto message_done;
p = (struct FZ1_Message *)msg;
command = its_an_fz1_message((UBYTE *)p,channel);
if (state == WAITING_FOR_OPEN)
{
if (command != OPEN_MIDI_MSG)
panic("out of sync - looking for 'Open' from FZ1");
/* we need to specify a channel ID in our messages
* if we're not looking for a specific one, reply
* with the one we got in the first message */
if (channel == -1)
channel = p->encoded_channel & 0x0f;
state = READING_FZ_DATA;
dump_open(p);
send_fz(source,channel,OK_MIDI_MSG);
goto message_done;
}
if (state == READING_FZ_DATA)
{
abort_timeout_timer();
switch(command)
{
case DATA_MIDI_MSG:
send_fz(source,channel,OK_MIDI_MSG);
start_timeout_timer();
packets_received++;
if ((packets_received % 10) == 0)
{
printf("%4d ok \r",packets_received);
fflush(stdout);
}
capture(p,outfd);
retry_count = 0;
break;
case DATA_ERROR:
data_error:
send_fz(source,channel,ERR_MIDI_MSG);
start_timeout_timer();
printf("%4d err\r",packets_received);
fflush(stdout);
error_count++;
if (++retry_count > MAX_RETRIES)
panic("exceeded max retries for a packet - transfer failed");
break;
/* we get this when the fz is done */
case CLOSE_MIDI_MSG:
fprintf(stderr,"casio is done\n");
done = 1;
break;
default:
fprintf(stderr,"unknown command = 0x%x\n",command);
if (state = READING_FZ_DATA)
{
fprintf(stderr,"will try treating it as a data error\n");
goto data_error;
}
else
panic("unknown command and not in 'read' mode");
}
goto message_done;
}
panic("state variable fried");
message_done: FreeMidiMsg(msg); /* free it */
}
if (CheckMsg(timer_request->tr_node.io_Message.mn_ReplyPort) &&
(GetMsg(timer_request->tr_node.io_Message.mn_ReplyPort)) )
{
if (state == READING_FZ_DATA)
{
send_fz(source,channel,ERR_MIDI_MSG);
printf("%4d tmo\r",packets_received);
fflush(stdout);
error_count++;
if (++retry_count > MAX_RETRIES)
panic("exceeded max retries for a packet - transfer failed");
}
}
}
if (capture_position != 0)
{
if (write(outfd,capture_buffer,capture_position) != capture_position)
perror("output file");
}
printf("total packets received %d (%d retries)\n",packets_received,error_count);
}
void send_fz(struct MSource *source, int channel_id, int message_id)
{
static UBYTE buf[] = {0xf0, 0x44, 0x02, 0x00, 0x70,0x00,0xf7};
buf[4] |= channel_id;
buf[5] = message_id;
PutMidiMsg(source,buf);
}
int calc_checksum(struct FZ1_Message *p)
{
UBYTE *ip, lownibble, hinibble;
int len, running_sum;
/* I assume the message has already been validated as a Casio FZ-1
* data message
*/
ip = &p->body.datamsg.data[0];
for (len = 0, running_sum = 0; len < 128; len++)
{
running_sum += *ip++;
}
return((0 - running_sum) & 0x7f);
}
void capture(struct FZ1_Message *p, int outfd)
{
UBYTE *ip, lownibble, hinibble;
int len;
ip = &p->body.datamsg.data[0];
for (len = 0; len < 64; len++)
{
lownibble = *ip++;
hinibble = *ip++;
capture_buffer[capture_position++] = (hinibble << 4) | lownibble;
if (capture_position >= CAPTURE_BUFFER_SIZE)
{
if (write(outfd,capture_buffer,CAPTURE_BUFFER_SIZE) != CAPTURE_BUFFER_SIZE)
{
perror("output file");
}
capture_position = 0;
}
}
}
struct MRouteInfo myrouteinfo =
{
MMF_SYSEX,0xffff,0,0,{0},{0}
};
main(int argc,char *argv[])
{
char *sname, *dname, *filename;
int outfd;
int wanted_channel = -1;
fprintf(stderr,"ready to talk to casio, the routes are done automatically from\n");
fprintf(stderr,"midi_in if it's available, else MidiIn and to MidiOut.\n");
fprintf(stderr,"I download and exit when done. I automatically do retries.\n");
fprintf(stderr,"Nonetheless, I may 'hang' when uploading. This is soft.\n");
fprintf(stderr,"Hit ^D to retry. Or hit ^C, I'll exit.\n");
fprintf(stderr,"I write to the file on the fly (every 256 packets), so watch it.\n");
if (argc != 2)
{
fprintf(stderr,"usage: casio filename, routes are automatic, then\n");
fprintf(stderr," select FZ output device as 'midi' and do a voice save\n");
exit(1);
}
sname = "FZ1out";
dname = "FZ1in";
filename = argv[1];
if ((outfd = creat(filename,0666)) == -1)
{
fprintf(stderr,"couldn't create output file\n");
perror(filename);
exit(2);
}
if (!(IntuitionBase = OpenLibrary("intuition.library",0)))
{
fprintf(stderr,"can't open intuition.library\n");
goto clean;
}
add_cleanup(midi_cleanup);
if (!(MidiBase = OpenLibrary(MIDINAME,MIDIVERSION)))
{
fprintf(stderr,"can't open midi.library\n");
goto clean;
}
/* create our public source node */
if (!(source = CreateMSource(sname,NULL)))
{
fprintf(stderr,"can't create Source port %s\n",sname);
goto clean;
}
/* create our dest node (public) */
if (!(dest = CreateMDest(dname,NULL)))
{
fprintf(stderr,"can't create Dest port %s\n",dname);
goto clean;
}
route_a = MRoutePublic("midi_in",dname,&myrouteinfo);
if (!route_a)
route_a = MRoutePublic("MidiIn",dname,&myrouteinfo);
route_b = MRoutePublic(sname,"MidiOut",&myrouteinfo);
init_timer();
commune_with_fz1(source,dest,wanted_channel,outfd); /* process until shutdown */
clean:
close(outfd);
cleanup();
exit(0);
}
void _abort(void) /* abort routine called when CTRL-C is hit (Aztec) */
{
/* fflush(stdout); cleanup(); exit(1); */
} /* we're polling it in the loop */
void dump_open(struct FZ1_Message *p)
{
unsigned int nblocks;
printf("dump of Open MIDI message received from Casio FZ-1\n");
printf("channel %d, status %d, ",p->encoded_channel & 0x0f,p->body.openmsg.status);
printf("banks %d, voices %d, ",p->body.openmsg.banks,p->body.openmsg.voices);
if(p->body.openmsg.status != 1 || p->body.openmsg.banks != 0
|| p->body.openmsg.voices != 1)
panic("I don't know how to do anything other than save a single voice");
nblocks = (p->body.openmsg.nblocks_hinibble << 12)
| (p->body.openmsg.nblocks_next_to_hinibble << 8)
| (p->body.openmsg.nblocks_next_to_lonibble << 4)
| p->body.openmsg.nblocks_lonibble;
printf("nblocks %d, ",nblocks);
printf("edit bank %d, edit voice %d\n",p->body.openmsg.edit_bank,p->body.openmsg.edit_voice);
}
/* end of casio.c */